package com.powerbank.device.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.powerbank.device.config.MqttConfig;
import com.powerbank.device.dto.DeviceCommandDTO;
import com.powerbank.device.dto.DeviceStatusDTO;
import com.powerbank.device.dto.SlotStatusDTO;
import com.powerbank.device.service.MqttMessageService;
import com.powerbank.device.service.DeviceHeartbeatService;
import com.powerbank.device.service.DeviceMonitorService;
import com.powerbank.device.service.impl.EnhancedDeviceCommunicationServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * MQTT消息服务实现类
 */
@Slf4j
@Service
public class MqttMessageServiceImpl implements MqttMessageService {

    @Autowired
    private MessageChannel mqttOutboundChannel;

    @Autowired
    private DeviceHeartbeatService heartbeatService;

    @Autowired
    private DeviceMonitorService deviceMonitorService;

    @Autowired
    private EnhancedDeviceCommunicationServiceImpl enhancedDeviceCommunicationService;

    @Override
    public boolean sendDeviceCommand(String deviceCode, DeviceCommandDTO command) {
        try {
            command.setCommandId(IdUtil.simpleUUID());
            command.setSendTime(LocalDateTime.now());
            
            String topic = MqttConfig.TOPIC_DEVICE_COMMAND + deviceCode;
            String payload = JSONUtil.toJsonStr(command);
            
            Message<String> message = MessageBuilder
                    .withPayload(payload)
                    .setHeader(MqttHeaders.TOPIC, topic)
                    .setHeader(MqttHeaders.QOS, 1)
                    .build();

            boolean sent = mqttOutboundChannel.send(message, 5000);
            
            if (sent) {
                log.info("发送设备指令成功 - 设备: {}, 指令: {}, ID: {}", 
                        deviceCode, command.getCommandType(), command.getCommandId());
            } else {
                log.error("发送设备指令失败 - 设备: {}, 指令: {}", deviceCode, command.getCommandType());
            }
            
            return sent;
        } catch (Exception e) {
            log.error("发送设备指令异常 - 设备: {}, 错误: {}", deviceCode, e.getMessage(), e);
            return false;
        }
    }

    // 注意：这个方法不是接口中定义的，所以不需要 @Override 注解
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public void handleMqttMessage(Message<String> message) {
        try {
            String topic = (String) message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC);
            String payload = message.getPayload();
            
            log.debug("收到MQTT消息 - 主题: {}, 内容: {}", topic, payload);
            
            if (topic.startsWith("powerbank/device/status/")) {
                String deviceCode = extractDeviceCodeFromTopic(topic);
                DeviceStatusDTO status = JSONUtil.toBean(payload, DeviceStatusDTO.class);
                handleDeviceStatus(deviceCode, status);
                
            } else if (topic.startsWith("powerbank/device/heartbeat/")) {
                String deviceCode = extractDeviceCodeFromTopic(topic);
                Long timestamp = Long.valueOf(payload);
                handleDeviceHeartbeat(deviceCode, timestamp);
                
            } else if (topic.startsWith("powerbank/device/response/")) {
                String deviceCode = extractDeviceCodeFromTopic(topic);
                handleDeviceResponse(deviceCode, payload);
                
            } else if (topic.startsWith("powerbank/slot/status/")) {
                String deviceCode = extractDeviceCodeFromTopic(topic);
                SlotStatusDTO slotStatus = JSONUtil.toBean(payload, SlotStatusDTO.class);
                handleSlotStatus(deviceCode, slotStatus);
            }
            
        } catch (Exception e) {
            log.error("处理MQTT消息异常: {}", e.getMessage(), e);
        }
    }

    @Override
    public void handleDeviceStatus(String deviceCode, DeviceStatusDTO status) {
        log.info("处理设备状态 - 设备: {}, 状态: {}, 在线: {}, 可用插槽: {}", 
                deviceCode, status.getDeviceStatus(), status.getOnlineStatus(), status.getAvailableSlots());
        
        // 更新设备状态缓存
        enhancedDeviceCommunicationService.updateDeviceStatusCache(deviceCode, status);
        
        // 检查设备状态异常
        if (status.getDeviceStatus() != 1) {
            log.warn("设备状态异常 - 设备: {}, 状态: {}, 错误: {}", 
                    deviceCode, status.getDeviceStatus(), status.getErrorMessage());
            // 创建设备故障报警
            deviceMonitorService.handleDeviceErrorAlert(deviceCode, status.getErrorCode(), status.getErrorMessage());
        }
        
        // 检查电量低报警
        if (status.getBatteryLevel() != null && status.getBatteryLevel() < 20) {
            log.warn("设备电量过低 - 设备: {}, 电量: {}%", deviceCode, status.getBatteryLevel());
            // 创建电量低报警
            deviceMonitorService.handleLowBatteryAlert(deviceCode, status.getBatteryLevel());
        }
    }

    @Override
    public void handleDeviceHeartbeat(String deviceCode, Long timestamp) {
        log.debug("收到设备心跳 - 设备: {}, 时间戳: {}", deviceCode, timestamp);
        
        // 更新设备心跳时间
        heartbeatService.updateHeartbeat(deviceCode);
        
        LocalDateTime heartbeatTime = LocalDateTime.now();
        log.debug("设备心跳正常 - 设备: {}, 心跳时间: {}", deviceCode, heartbeatTime);
    }

    @Override
    public void handleSlotStatus(String deviceCode, SlotStatusDTO slotStatus) {
        log.info("处理插槽状态 - 设备: {}, 插槽: {}, 状态: {}, 锁定: {}", 
                deviceCode, slotStatus.getSlotNo(), slotStatus.getSlotStatus(), slotStatus.getLockStatus());
        
        // 更新插槽状态缓存
        enhancedDeviceCommunicationService.updateSlotStatusCache(deviceCode, slotStatus);
        
        // 检查插槽故障
        if (slotStatus.getSlotStatus() == 2) {
            log.warn("插槽故障 - 设备: {}, 插槽: {}, 错误: {}", 
                    deviceCode, slotStatus.getSlotNo(), slotStatus.getErrorMessage());
            // 创建插槽故障报警
            deviceMonitorService.handleSlotErrorAlert(deviceCode, slotStatus.getSlotNo(), 
                    slotStatus.getErrorCode(), slotStatus.getErrorMessage());
        }
    }

    @Override
    public void handleDeviceResponse(String deviceCode, String response) {
        log.info("收到设备响应 - 设备: {}, 响应: {}", deviceCode, response);
        
        try {
            // 简单解析响应格式：{"commandId":"xxx","result":"success","message":"xxx"}
            if (response.contains("commandId") && response.contains("result")) {
                // 提取commandId和result
                String commandId = extractJsonValue(response, "commandId");
                String result = extractJsonValue(response, "result");
                
                if (commandId != null && result != null) {
                    // 更新指令执行结果
                    String finalResult = "success".equalsIgnoreCase(result) ? "SUCCESS" : "FAILED";
                    enhancedDeviceCommunicationService.updateCommandResult(commandId, finalResult);
                    
                    log.info("更新指令执行结果 - 指令ID: {}, 结果: {}", commandId, finalResult);
                }
            }
            
            log.debug("设备响应处理完成 - 设备: {}", deviceCode);
        } catch (Exception e) {
            log.error("解析设备响应失败 - 设备: {}, 响应: {}, 错误: {}", deviceCode, response, e.getMessage());
        }
    }
    
    /**
     * 从 JSON 字符串中提取指定键的值
     */
    private String extractJsonValue(String json, String key) {
        try {
            int keyIndex = json.indexOf('"' + key + '"');
            if (keyIndex == -1) {
                return null;
            }
            
            int colonIndex = json.indexOf(':', keyIndex);
            if (colonIndex == -1) {
                return null;
            }
            
            int startIndex = json.indexOf('"', colonIndex) + 1;
            int endIndex = json.indexOf('"', startIndex);
            
            if (startIndex > 0 && endIndex > startIndex) {
                return json.substring(startIndex, endIndex);
            }
            
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public boolean sendUnlockCommand(String deviceCode, Integer slotNo) {
        DeviceCommandDTO command = new DeviceCommandDTO();
        command.setCommandType("UNLOCK");
        command.setDeviceCode(deviceCode);
        command.setSlotNo(slotNo);
        command.setTimeout(30);
        command.setPriority(1); // 高优先级
        
        return sendDeviceCommand(deviceCode, command);
    }

    @Override
    public boolean sendLockCommand(String deviceCode, Integer slotNo) {
        DeviceCommandDTO command = new DeviceCommandDTO();
        command.setCommandType("LOCK");
        command.setDeviceCode(deviceCode);
        command.setSlotNo(slotNo);
        command.setTimeout(30);
        command.setPriority(1); // 高优先级
        
        return sendDeviceCommand(deviceCode, command);
    }

    @Override
    public boolean queryDeviceStatus(String deviceCode) {
        DeviceCommandDTO command = new DeviceCommandDTO();
        command.setCommandType("QUERY_STATUS");
        command.setDeviceCode(deviceCode);
        command.setTimeout(10);
        command.setPriority(2); // 普通优先级
        
        return sendDeviceCommand(deviceCode, command);
    }

    @Override
    public boolean querySlotStatus(String deviceCode, Integer slotNo) {
        DeviceCommandDTO command = new DeviceCommandDTO();
        command.setCommandType("QUERY_SLOT");
        command.setDeviceCode(deviceCode);
        command.setSlotNo(slotNo);
        command.setTimeout(10);
        command.setPriority(2); // 普通优先级
        
        return sendDeviceCommand(deviceCode, command);
    }

    /**
     * 从MQTT主题中提取设备编码
     */
    private String extractDeviceCodeFromTopic(String topic) {
        String[] parts = topic.split("/");
        return parts[parts.length - 1];
    }
}